<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <!--作业1 手写Promise -->
    <script>
      // 4.定义变量方便后期维护
      const PENDING = "pending";
      const FULFILLED = "fulfilled";
      const REJECTED = "rejected";

      class MyPromise {
        // 4.私有属性
        #state = "pending"; //存状态
        #result = undefined; //参数存结果
        #handers = [];
        // 1 .启动了promise,传入一个函数
        constructor(executor) {
          // 3.传递参数和错误原因
          const resolve = (data) => {
            this.#changeState(FULFILLED, data);
          };
          const reject = (reason) => {
            this.#changeState(REJECTED, reason);
          };

          //   5.将执行函数错误捕获,当成参数传进去
          try {
            // 2.同步调用  其中俩个参数是函数
            executor(resolve, reject);
          } catch (err) {
            reject(err);
          }
        }

        #changeState = (state, result) => {
          if (this.#state !== "PENDING") return;
          this.#state = state;
          this.#result = result;
          this.#run();
        };

        #isPromiseLike(value) {
          if (
            value !== null &&
            (typeof value === "object" || typeof value === "function")
          ) {
            return typeof value.then === "function";
          }
          return false;
        }

        #runMicroTask(func) {
          setTimeout(func, 0);
        }

        #runOne(callback, resolve, reject) {
          this.#runMicroTask(() => {
            if (typeof callback !== "function") {
              const settled = this.#state === FULFILLED ? resolve : reject;
              settled(this.#result);
              return;
            }
            try {
              const data = callback(this.#result);
              if (this.#isPromiseLike(data)) {
                data.then(resolve, reject);
              } else {
                resolve(data);
              }
              resolve(data);
            } catch (err) {
              reject(err);
            }
          });
        }

        // 执行属性内保存的东西
        #run() {
          if (this.#state === "PENDING") return;
          while (this.#handers.length) {
            const { onFulfilled, onRejected, resolve, reject } =
              this.#handers.shift();
            if (this.#state === FULFILLED) {
              this.#runOne(onFulfilled, resolve, reject);
            } else {
              this.#runOne(onRejected, resolve, reject);
            }
          }
        }

        //   6.then方法的实现
        //   (1)什么时候onFulfilled onRejected调用
        then(onFulfilled, onRejected) {
          return new MyPromise((resolve, reject) => {
            this.#handers.push({
              onFulfilled,
              onRejected,
              resolve,
              reject,
            });
            this.#run();
          });
        }

        catch(onRejected) {
          return this.then(null, onRejected);
        }
      }

      const p = new MyPromise((resolve, reject) => {
        reject(1);
      });

      p.then(
        (res) => {
          console.log(res);
        },
        (err) => {
          console.log(err);
        }
      );
    </script>

    <!-- 作业2 -->
    <!-- <script>
      async function asyncFn() {
        try {
          const result = await new MyPromise((resolve, reject) => {
            // 模拟异步操作
            setTimeout(() => resolve("成功"), 1000);
          });
          console.log(result);
        } catch (error) {
          console.error("错误:", error);
        }
      }
      asyncFn();
    </script> -->

    <!-- 作业3 -->
    <!-- <script>
      class Rectangle {
        constructor(width, height) {
          this.width = width;
          this.height = height;
        }

        area() {
          return this.width * this.height;
        }

        long() {
          return 2 * (this.width + this.height);
        }
      }

      // 示例
      const rect = new Rectangle(10, 5);
      console.log("面积:", rect.area());
      console.log("周长:", rect.long());
    </script> -->
  </body>
</html>
